﻿using System;
using System.Globalization;
using System.IO;
using System.Linq;

using Supremacy.Data;
using Supremacy.Game;

namespace Supremacy.Resources
{
    public interface IResourceManagerService
    {
        #region Properties and Indexers
        GameMod CurrentMod { get; }
        #endregion

        #region Methods
        string GetInternalResourcePath(string path);
        string GetResourcePath(string path);
        Uri GetResourceUri(string path);
        string GetString(string key);
        string GetSystemResourcePath(string path);
        void Initialize();
        #endregion
    }

    public class ResourceManagerService : IResourceManagerService
    {
        #region Constants
        public const char PathSeparatorCharacter = ':';
        #endregion

        #region Fields
        public readonly CultureInfo CurrentCulture;
        public readonly CultureInfo NeutralCulture;
        public readonly string NeutralLocale;
        public string CurrentLocale;
        private readonly GameMod s_commandLineMod;

        private readonly StringTable s_defaultStrings;
        private readonly StringTable s_localStrings;
        private readonly string s_workingDirectory;
        #endregion

        #region Constructors
        public ResourceManagerService()
        {
            s_workingDirectory = PathHelper.GetWorkingDirectory();

            AppDomain.CurrentDomain.SetData("DataDirectory", s_workingDirectory);

            NeutralCulture = CultureInfo.GetCultureInfo("en");
            CurrentCulture = CultureInfo.CurrentCulture;

            while (!CurrentCulture.IsNeutralCulture && (CurrentCulture.Parent != null))
                CurrentCulture = CurrentCulture.Parent;

            NeutralLocale = NeutralCulture.Name;
            CurrentLocale = CurrentCulture.Name;

            s_commandLineMod = GameModLoader.GetModFromCommandLine();

            s_defaultStrings = StringTable.Load(
                GetResourcePath(@"Resources\Strings\" + NeutralLocale + ".txt"));

            if (CurrentLocale == NeutralLocale)
            {
                s_localStrings = null;
            }
            else
            {
                try
                {
                    s_localStrings = StringTable.Load(
                        GetResourcePath(@"Resources\Strings\" + CurrentLocale + ".txt"));
                }
                catch {}
            }
        }
        #endregion

        #region Methods
        private static string EvaluateRelativePath(string mainDirPath, string absoluteFilePath)
        {
            mainDirPath = mainDirPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
            absoluteFilePath = absoluteFilePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);

            var firstPathParts = mainDirPath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);
            var secondPathParts = absoluteFilePath.Trim(Path.DirectorySeparatorChar).Split(Path.DirectorySeparatorChar);

            int sameCounter = 0;
            for (int i = 0; i < Math.Min(firstPathParts.Length, secondPathParts.Length); i++)
            {
                if (!firstPathParts[i].ToLower().Equals(secondPathParts[i].ToLower()))
                {
                    break;
                }
                sameCounter++;
            }

            if (sameCounter == 0)
            {
                while (absoluteFilePath.StartsWith("." + Path.DirectorySeparatorChar))
                    absoluteFilePath = absoluteFilePath.Substring(2);
                return absoluteFilePath;
            }

            string newPath = String.Empty;
            for (int i = sameCounter; i < firstPathParts.Length; i++)
            {
                if (i > sameCounter)
                {
                    newPath += Path.DirectorySeparatorChar;
                }
                newPath += "..";
            }
            if (newPath.Length == 0)
            {
                newPath = ".";
            }
            for (int i = sameCounter; i < secondPathParts.Length; i++)
            {
                newPath += Path.DirectorySeparatorChar;
                newPath += secondPathParts[i];
            }

            while (newPath.StartsWith("." + Path.DirectorySeparatorChar))
                newPath = newPath.Substring(2);

            return newPath;
        }

        private static string GetInternalPathFormat(string path)
        {
            path = path.Replace(Path.DirectorySeparatorChar, PathSeparatorCharacter);
            path = path.Replace(Path.AltDirectorySeparatorChar, PathSeparatorCharacter);
            return path;
        }

        private static string GetSystemPathFormat(string path)
        {
            path = path.Replace(PathSeparatorCharacter, Path.DirectorySeparatorChar);
            path = path.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
            return path;
        }
        #endregion

        #region IResourceManagerService Members
        public GameMod CurrentMod
        {
            get
            {
                if (s_commandLineMod != null)
                    return s_commandLineMod;
                if (GameContext.Current != null)
                    return GameContext.Current.GameMod;
                return null;
            }
        }

        public void Initialize()
        {
            return;
        }

        public string GetString(string key)
        {
            string result = null;
            if (s_localStrings != null)
            {
                result = s_localStrings[key];
            }
            if (result == null)
            {
                result = s_defaultStrings[key];
            }
            return result ?? key;
        }

        public string GetResourcePath(string path)
        {
            return GetSystemResourcePath(path);
        }

        public string GetInternalResourcePath(string path)
        {
            if (path == null)
                return null;
            path = EvaluateRelativePath(s_workingDirectory, GetSystemPathFormat(path));
            if (CurrentMod != null)
            {
                string modRelativePath = GetSystemPathFormat(CurrentMod.RootPath);
                string modAbsolutePath;
                if (Path.IsPathRooted(modRelativePath))
                {
                    modAbsolutePath = modRelativePath;
                    modRelativePath = EvaluateRelativePath(s_workingDirectory, modRelativePath);
                }
                else
                {
                    modAbsolutePath = Path.Combine(s_workingDirectory, modRelativePath);
                }
                if (File.Exists(modAbsolutePath))
                {
                    return GetInternalPathFormat(modRelativePath);
                }
            }
            return GetInternalPathFormat(Path.Combine(s_workingDirectory, path));
        }

        public string GetSystemResourcePath(string path)
        {
            if (path == null)
                return null;
            if (Path.IsPathRooted(path))
                path = EvaluateRelativePath(s_workingDirectory, path);
            if (CurrentMod != null)
            {
                string modPath = GetSystemPathFormat(CurrentMod.RootPath);
                if (!Path.IsPathRooted(modPath))
                {
                    modPath = Path.Combine(s_workingDirectory, modPath);
                }
                if (Directory.Exists(modPath))
                {
                    string modFile = EvaluateRelativePath(s_workingDirectory, Path.Combine(modPath, path));
                    if (File.Exists(modFile))
                        return modFile;
                }
            }
            return EvaluateRelativePath(s_workingDirectory, GetSystemPathFormat(path));
        }

        public Uri GetResourceUri(string path)
        {
            if (path == null)
                return null;
            return new Uri("file:///" + Path.GetFullPath(GetSystemResourcePath(path)), UriKind.Absolute);
        }
        #endregion
    }
}